import json
import time
import subprocess
import psutil
import paho.mqtt.client as mqtt
def upload_static_data(iot):
    #固定指标,可以从文本读取
    iot.report_property("xjNo", "AIoT-tj")
    #一体机sn
    iot.report_property("simNo", "89757")
    iot.report_property("powerMode", 1)
    iot.report_property("manufacturer", "中国联通")
    iot.report_property("deviceType", "Kunpeng 920 5220")
    iot.report_property("collectionTime", 300)
    iot.report_property("heartBeatTime", 60)
    iot.report_property("softwareVersion", "openEuler 22.03 (LTS-SP4)")
    
def get_ipmi():
    cmd = [
    "ipmitool", 
    "-I", "open",   
    "sensor"       
    ]
    result = subprocess.run(cmd, capture_output=True, text=True)
    return result.stdout

def filter_temp_cpu(output_str):
    cpu_temps = {}
    for line in output_str.splitlines():
        if not line.strip():
            continue
        parts = [p.strip() for p in line.split("|")]
        if len(parts) < 2:
            continue
        name = parts[0]
        if name in ["CPU1 MEM Temp", "CPU2 MEM Temp"]:
            temp_str = parts[1]
            try:
                temp_val = float(temp_str)
                cpu_temps[name.lower().replace(" ", "_")] = temp_val  # 保留小数
            except ValueError:
                pass

    cpu1 = cpu_temps.get("cpu1_mem_temp", "N/A")
    cpu2 = cpu_temps.get("cpu2_mem_temp", "N/A")

    return f"cpu1: {cpu1} cpu2: {cpu2}"

def filter_fan_speeds_grouped(output_str):
    fans = {
        "FAN1 Speed": None,
        "FAN2 Speed": None,
        "FAN3 Speed": None,
        "FAN4 Speed": None,
    }
    for line in output_str.splitlines():
        parts = [p.strip() for p in line.split("|")]
        if len(parts) < 2:
            continue
        name = parts[0]
        if name in fans:
            try:
                fans[name] = int(float(parts[1]))
            except ValueError:
                fans[name] = None

    group1 = f"风扇一 {fans['FAN1 Speed'] or 'N/A'} 风扇二 {fans['FAN2 Speed'] or 'N/A'}"
    group2 = f"风扇三 {fans['FAN3 Speed'] or 'N/A'} 风扇四 {fans['FAN4 Speed'] or 'N/A'}"
    return group1, group2

def filter_power(output_str):
    for line in output_str.splitlines():
        parts = [p.strip() for p in line.split("|")]
        if len(parts) > 1 and parts[0].lower() == "power":
            try:
                return float(parts[1])
            except ValueError:
                return None
    return None

def upload_bmc_data(iot):
    result_ipmi = get_ipmi()
    iot.report_property("temp_cpu", filter_temp_cpu(result_ipmi))
    iot.report_property("power", f"{filter_power(result_ipmi)}w")
    group1_str, group2_str = filter_fan_speeds_grouped(result_ipmi)
    iot.report_property("fans1", group1_str)   
    iot.report_property("fans2", group2_str) 
    
def upload_sys_data(iot):
    ps_result = get_system_status()
    iot.report_property("cpu_load", f"{ps_result['cpu_percent']}%") 
    vm = ps_result['virtual_memory']
    vm_str = f"总: {vm['总']}GB, 可用: {vm['可用']}GB"
    iot.report_property("mem", vm_str)

    sys_use = ps_result['disk_usage']['system_disk']
    sys_str = f"总: {sys_use['总']}GB, 可用: {sys_use['可用']}GB"
    iot.report_property("sysdisk", sys_str)
   
    data_use = ps_result['disk_usage']['data_disk']
    data_str = f"总: {data_use['总']}GB, 可用: {data_use['可用']}GB"
    iot.report_property("datadisk", data_str)

def bytes_to_gb(bytes_value):
    return round(bytes_value / (1024 ** 3), 2)  # 转成GB，保留两位小数

def get_disk_usage(path):
    try:
        usage = psutil.disk_usage(path)
        return {
            '总': bytes_to_gb(usage.total),
            #'used_gb': bytes_to_gb(usage.used),
            '可用': bytes_to_gb(usage.free),
            #'percent': usage.percent
        }
    except Exception:
        return None  # 路径不存在或访问异常时返回None

def get_system_status():
    status = {}

    # CPU占用百分比
    status['cpu_percent'] = psutil.cpu_percent(interval=1)

    # 内存信息
    vm = psutil.virtual_memory()
    status['virtual_memory'] = {
        '总': bytes_to_gb(vm.total),
        '可用': bytes_to_gb(vm.available),
        #'used_gb': bytes_to_gb(vm.used),
        #'percent': vm.percent
    }

    # 交换内存
    sm = psutil.swap_memory()
    status['swap_memory'] = {
        'total_gb': bytes_to_gb(sm.total),
        'used_gb': bytes_to_gb(sm.used),
        'free_gb': bytes_to_gb(sm.free),
        'percent': sm.percent
    }

    # 磁盘使用，系统盘和/data盘
    status['disk_usage'] = {}
    # 系统盘（根目录'/')
    system_disk = get_disk_usage('/')
    if system_disk:
        status['disk_usage']['system_disk'] = system_disk
    else:
        status['disk_usage']['system_disk'] = 'Unavailable'

    # /data盘
    data_disk = get_disk_usage('/data')
    if data_disk:
        status['disk_usage']['data_disk'] = data_disk
    else:
        status['disk_usage']['data_disk'] = 'Unavailable'

    return status

class IoTClient:
    def __init__(self, broker, port, productKey, deviceKey, clientId, username, password, use_tls=False):
        self.productKey = productKey
        self.deviceKey = deviceKey
        self.client = mqtt.Client(client_id=clientId, clean_session=True)
        self.client.username_pw_set(username, password)

        if use_tls:
            self.client.tls_set()

        # 连接服务器
        self.client.connect(broker, port, keepalive=60)
        self.client.loop_start()

    def report_property(self, key, value, ts=None, qos=1):
        pub_topic = f"$sys/{self.productKey}/{self.deviceKey}/property/pub"
        message_id = str(int(time.time() * 1000))
        payload = {
            "messageId": message_id,
            "params": {
                "key": key,
                "value": value,
                "ts": ts if ts else str(int(time.time() * 1000))
            }
        }
        result = self.client.publish(pub_topic, json.dumps(payload), qos=qos)
        result.wait_for_publish()
        print(f"[Publish] topic={pub_topic}")
        print(f"[Payload] {json.dumps(payload)}")

    def close(self):
        self.client.loop_stop()
        self.client.disconnect()

if __name__ == "__main__":
    # 示例参数（替换成你的实际值）
    broker = "dmp-mqtt.cuiot.cn"
    port = 1883
    productKey = "cu1cefqr73hy9q5F"
    deviceKey = "Ndikyud5WLgpywD"

    clientId = "SN1234567890|cu1cefqr73hy9q5F|0|0|0"
    username = "Ndikyud5WLgpywD|cu1cefqr73hy9q5F"
    password = "2e4d6f8bd70ca801830348cabb77ab74a5df59eb65a35f31a1cec031376aacd4"

    iot = IoTClient(broker, port, productKey, deviceKey, clientId, username, password)
    upload_static_data(iot)
    while True:
        #upload_static_data(iot)
        upload_bmc_data(iot)
        upload_sys_data(iot)
        time.sleep(60)
